package com.jwong.grpc.loadbalancer;

import com.jwong.grpc.hellolb.GreeterLBGrpc;
import com.jwong.grpc.hellolb.HelloLBReply;
import com.jwong.grpc.hellolb.HelloLBRequest;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 一个简单的给定静态服务的客户端负载均衡，对于动态的服务发现，我们应该在forTarget中给定服务注册的地址
 * 并在NameResolver中在注册服务列表中提取name给GRPC客户端（比如：将kubernetes service 解析为 endpoints），
 */
public class GreeterGrpcLBClient {

    private static int THREADS = 4;
    private static Random RANDOM = new Random();

    private final GreeterLBGrpc.GreeterLBBlockingStub blockingStub;

    public GreeterGrpcLBClient(ManagedChannel channel) {
        blockingStub = GreeterLBGrpc.newBlockingStub(channel);
    }

    public static void main(String[] args) throws UnknownHostException {
        ManagedChannel channel = ManagedChannelBuilder
                .forTarget("direct://localhost:8000,direct://localhost:9000")
                 // nameResolverFactory() 方法被标注为@Deprecated， 我们应该使用SPI的方式
                // .nameResolverFactory(new DirectMultiAddressNameResolverProvider())
                // 对于我们自定义的LoadBalancer，也应该使用SPI的方式提供
                .defaultLoadBalancingPolicy("round_robin")
                .usePlaintext()
                .build();


        final String self = InetAddress.getLocalHost().getHostName();

        ExecutorService executorService = Executors.newFixedThreadPool(THREADS);
        for (int i = 0; i < THREADS; i++) {
            GreeterGrpcLBClient client = new GreeterGrpcLBClient(channel);
            executorService.submit(() -> {
                while (true) {
                    HelloLBReply response = client.sayHello(self + ": " + Thread.currentThread().getName());
                    System.out.println(response);
                    Thread.sleep(RANDOM.nextInt(700));
                }
            });
        }
    }

    public HelloLBReply sayHello(String name) {
        return blockingStub.sayHello(
                HelloLBRequest.newBuilder()
                        .setName(name)
                        .build());
    }

}
